from configparser import SectionProxy
from azure.identity import DeviceCodeCredential
from azure.core.credentials import AccessToken
from msgraph import GraphServiceClient
from msgraph.generated.users.item.user_item_request_builder import UserItemRequestBuilder
from msgraph.generated.users.item.mail_folders.item.messages.messages_request_builder import (
    MessagesRequestBuilder)
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import (
    SendMailPostRequestBody)
from msgraph.generated.models.message import Message
from msgraph.generated.models.item_body import ItemBody
from msgraph.generated.models.body_type import BodyType
from msgraph.generated.models.recipient import Recipient
from msgraph.generated.models.email_address import EmailAddress
from datetime import datetime, timedelta
import time

class StaticTokenCredential:
    """
    自定义令牌凭据类 - 使用预存的访问令牌
    符合Azure Core TokenCredential协议
    """
    def __init__(self, access_token: str):
        self.access_token = access_token
        # 设置令牌过期时间（通常为1小时）
        self.expires_on = datetime.now() + timedelta(hours=1)
    
    def get_token(self, *scopes, claims=None, tenant_id=None, enable_cae=False, **kwargs):
        """
        返回访问令牌
        符合TokenCredential协议的get_token方法签名
        
        Args:
            *scopes: 请求的权限范围
            claims: 额外的声明要求
            tenant_id: 可选的租户ID
            enable_cae: 是否启用连续访问评估
            **kwargs: 其他关键字参数
            
        Returns:
            AccessToken: 包含令牌字符串和过期时间的AccessToken实例
        """
        return AccessToken(self.access_token, int(self.expires_on.timestamp()))

class Graph:
    settings: SectionProxy
    device_code_credential: DeviceCodeCredential
    static_credential: StaticTokenCredential
    user_client: GraphServiceClient
    use_static_token: bool

    def __init__(self, config: SectionProxy, use_stored_token: bool = True):
        """
        初始化Graph客户端
        
        Args:
            config: 配置文件节
            use_stored_token: 是否使用存储的令牌（默认True）
        """
        self.settings = config
        client_id = self.settings['clientId']
        tenant_id = self.settings['tenantId']
        graph_scopes = self.settings['graphUserScopes'].split(' ')
        self.use_static_token = use_stored_token
        
        # 检查是否有存储的令牌且选择使用它
        if use_stored_token and 'token' in self.settings and self.settings['token'].strip():
            print('使用配置文件中的存储令牌进行身份验证...')
            self.static_credential = StaticTokenCredential(self.settings['token'])
            self.user_client = GraphServiceClient(self.static_credential, graph_scopes)
        else:
            print('使用设备代码流进行身份验证...')
            self.device_code_credential = DeviceCodeCredential(client_id, tenant_id = tenant_id)
            self.user_client = GraphServiceClient(self.device_code_credential, graph_scopes)
            self.use_static_token = False

    async def get_user_token(self):
        """
        获取用户访问令牌
        
        Returns:
            str: 访问令牌字符串
        """
        if self.use_static_token:
            return self.static_credential.access_token
        else:
            graph_scopes = self.settings['graphUserScopes']
            access_token = self.device_code_credential.get_token(graph_scopes)
            # 保存新获取的token到配置文件
            self.save_token_to_config(access_token.token)
            return access_token.token
    
    def save_token_to_config(self, token):
        """
        将token保存到配置文件
        
        Args:
            token: 要保存的访问令牌
        """
        import configparser
        import os
        
        # 读取当前配置
        config = configparser.ConfigParser()
        config_path = 'config.cfg'
        if os.path.exists(config_path):
            config.read([config_path], encoding='utf-8')
            
            # 更新token
            if 'azure' in config:
                config['azure']['token'] = token
                
                # 写回配置文件
                with open(config_path, 'w', encoding='utf-8') as f:
                    config.write(f)
                print('Token已更新到配置文件。')

    async def get_user(self):
    # Only request specific properties using $select
        query_params = UserItemRequestBuilder.UserItemRequestBuilderGetQueryParameters(
            select=['displayName', 'mail', 'userPrincipalName']
        )
        request_config = UserItemRequestBuilder.UserItemRequestBuilderGetRequestConfiguration(
            query_parameters=query_params
        )

        user = await self.user_client.me.get(request_configuration=request_config)
        return user

    async def get_inbox(self):
        query_params = MessagesRequestBuilder.MessagesRequestBuilderGetQueryParameters(
            # Only request specific properties
            select=['from', 'isRead', 'receivedDateTime', 'subject'],
            # Get at most 25 results
            top=25,
            # Sort by received time, newest first
            orderby=['receivedDateTime DESC']
        )
        request_config = MessagesRequestBuilder.MessagesRequestBuilderGetRequestConfiguration(
            query_parameters= query_params
        )

        messages = await self.user_client.me.mail_folders.by_mail_folder_id('inbox').messages.get(
                request_configuration=request_config)
        return messages

    async def send_mail(self, subject: str, body: str, recipient: str):
        message = Message()
        message.subject = subject

        message.body = ItemBody()
        message.body.content_type = BodyType.Text
        message.body.content = body

        to_recipient = Recipient()
        to_recipient.email_address = EmailAddress()
        to_recipient.email_address.address = recipient
        message.to_recipients = []
        message.to_recipients.append(to_recipient)

        request_body = SendMailPostRequestBody()
        request_body.message = message

        await self.user_client.me.send_mail.post(body=request_body)

